package org.erikaredmark.monkeyshines.menu;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JDialog;
import javax.swing.JPanel;
import org.erikaredmark.monkeyshines.global.SoundType;
import org.erikaredmark.monkeyshines.global.SoundUtils;
/**
*
* Primary dialog for modifying the sound levels of both sound and music (which once is based on
* the passed launching parameter). As with other game dialogs, this uses an absolute layout to
* best recreate the original game.
*
* @author Erika Redmark
*
*/
public final class SoundControlDialog extends JDialog {
private static final long serialVersionUID = 1L;
private final BufferedImage SOUND_LEFT_SIDE;
private final BufferedImage SOUND_RIGHT_SIDE;
private final BufferedImage MUSIC_LEFT_SIDE;
private final BufferedImage MUSIC_RIGHT_SIDE;
private final BufferedImage BACKGROUND;
// Whenever the sound levels are changed, the sound demo is played at the appropriate
// gain to demonstrate to the player an idea of how loud or soft they just made things
private final Clip SOUND_DEMO;
// Icons that flank the main slider will show either the music of general sound
// icon to indicate low to high sound.
private static final int LEFT_SIDE_DRAW_X = 40;
private static final int LEFT_SIDE_DRAW_Y = 47;
private static final int LEFT_SIDE_DRAW_X2 = 78;
private static final int LEFT_SIDE_DRAW_Y2 = 84;
private static final int RIGHT_SIDE_DRAW_X = 253;
private static final int RIGHT_SIDE_DRAW_Y = 47;
private static final int RIGHT_SIDE_DRAW_X2 = 291;
private static final int RIGHT_SIDE_DRAW_Y2 = 84;
// Sliders controls location
private static final int SLIDER_DRAW_X = 78;
private static final int SLIDER_DRAW_Y = 52;
private static final int SLIDER_WIDTH = 175;
private static final int SLIDER_HEIGHT = 29;
// Button location
private static final int OKAY_DRAW_X = 133;
private static final int OKAY_DRAW_Y = 118;
private static final int DIALOG_SIZE_X = 328;
private static final int DIALOG_SIZE_Y = 180;
private SoundControlDialog(final SoundType type)
throws SoundControlDialogInitException {
// ------------------------- Ensure construction is possible
try {
// Graphics
SOUND_LEFT_SIDE = ImageIO.read(SoundControlDialog.class.getResourceAsStream("/resources/graphics/mainmenu/sound/soundLeftSide.png") );
SOUND_RIGHT_SIDE = ImageIO.read(SoundControlDialog.class.getResourceAsStream("/resources/graphics/mainmenu/sound/soundRightSide.png") );
MUSIC_LEFT_SIDE = ImageIO.read(SoundControlDialog.class.getResourceAsStream("/resources/graphics/mainmenu/sound/musicLeftSide.png") );
MUSIC_RIGHT_SIDE = ImageIO.read(SoundControlDialog.class.getResourceAsStream("/resources/graphics/mainmenu/sound/musicRightSide.png") );
BACKGROUND = ImageIO.read(SoundControlDialog.class.getResourceAsStream("/resources/graphics/mainmenu/sound/soundMain.png") );
// Sound
SOUND_DEMO = SoundUtils.clipFromOggStream(SoundControlDialog.class.getResourceAsStream("/resources/sounds/mainmenu/soundDemo.ogg"), "soundDemo.ogg");
} catch (IOException e) {
throw new SoundControlDialogInitException(
"Bad .jar, could not find graphics resources for sound system: " + e.getMessage(), e);
} catch (UnsupportedAudioFileException e) {
throw new SoundControlDialogInitException(
"Bad .jar, demo sound not in .ogg format: " + e.getMessage(), e);
} catch (LineUnavailableException e) {
throw new SoundControlDialogInitException(
"No sound device available: " + e.getMessage(), e);
} catch (Exception e) {
throw new SoundControlDialogInitException(
"Unable to Access Sound Device: " + e.getMessage(), e);
}
// ------------------------- Visuals
// add a JPanel containing all the components. We can custom paint the JPanel with
// added components easier than we can with a dialog class.
JPanel mainPanel = new JPanel() {
private static final long serialVersionUID = 1L;
// Direct painting is responsible for background and left/right sound images
@Override public void paintComponent(Graphics g) {
g.drawImage(BACKGROUND,
0, 0,
BACKGROUND.getWidth(), BACKGROUND.getHeight(),
0, 0,
BACKGROUND.getWidth(), BACKGROUND.getHeight(),
null);
// Switch statement over polymorphism, as this class is responsible for maintaining the
// graphics resources, not the static enum.
BufferedImage leftSide = null;
BufferedImage rightSide = null;
switch(type) {
case MUSIC:
leftSide = MUSIC_LEFT_SIDE;
rightSide = MUSIC_RIGHT_SIDE;
break;
case SOUND:
leftSide = SOUND_LEFT_SIDE;
rightSide = SOUND_RIGHT_SIDE;
break;
default:
throw new RuntimeException("Unknown soundtype " + type);
}
assert leftSide != null;
assert rightSide != null;
g.drawImage(leftSide,
LEFT_SIDE_DRAW_X, LEFT_SIDE_DRAW_Y,
LEFT_SIDE_DRAW_X2, LEFT_SIDE_DRAW_Y2,
0, 0,
leftSide.getWidth(), leftSide.getHeight(),
null);
g.drawImage(rightSide,
RIGHT_SIDE_DRAW_X, RIGHT_SIDE_DRAW_Y,
RIGHT_SIDE_DRAW_X2, RIGHT_SIDE_DRAW_Y2,
0, 0,
rightSide.getWidth(), rightSide.getHeight(),
null);
}
};
mainPanel.setLocation(0, 0);
mainPanel.setSize(DIALOG_SIZE_X, DIALOG_SIZE_Y);
mainPanel.setPreferredSize(new Dimension(DIALOG_SIZE_X, DIALOG_SIZE_Y) );
mainPanel.setMinimumSize(new Dimension(DIALOG_SIZE_X, DIALOG_SIZE_Y) );
mainPanel.setLayout(null);
add(mainPanel);
// Only the slider and button are components. Everything else is painted in the paint method.
VolumeSlider volumeSlider = new VolumeSlider(type, SOUND_DEMO);
volumeSlider.setLocation(SLIDER_DRAW_X, SLIDER_DRAW_Y);
volumeSlider.setSize(SLIDER_WIDTH, SLIDER_HEIGHT);
mainPanel.add(volumeSlider);
OkayButton okayButton = new OkayButton(new ActionListener() {
@Override public void actionPerformed(ActionEvent arg0) {
// close window. All changes from slider have already propogated.
setVisible(false);
}
});
okayButton.setLocation(OKAY_DRAW_X, OKAY_DRAW_Y);
mainPanel.add(okayButton);
}
/**
*
* Launches the sound control dialog for the user to modify the sound. This dialog is modal, so
* control will not return from this method until the user closes the dialog.
* <p/>
* Clients should call {@code SoundSettings.persist() } after the dialog has launched if they want
* to save the settings to the disk. Settings are not saved whilst the user is playing with the
* sliders.
*
* @throws SoundControlDialogInitException
* creating the dialog may fail, if sound system cannot even be
* created, in those cases, this dialog should not launch, and client
* should display an informative error dialog.
*
*/
public static void launch(final SoundType sound)
throws SoundControlDialogInitException {
SoundControlDialog dialog = new SoundControlDialog(sound);
dialog.setUndecorated(true);
dialog.setModal(true);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
}
}